﻿//========================================================= 
/**@file ICCardCmdDriver.h
 * @brief IC卡命令
 * 
 * @date 2016-04-14   10:15:45
 * @author Zhyioo 
 * @version 1.0
 */ 
//--------------------------------------------------------- 
#ifndef _LIBZHOUYB_ICCARDCMDDRIVER_H_
#define _LIBZHOUYB_ICCARDCMDDRIVER_H_
//--------------------------------------------------------- 
#include "../CommonCmdDriver.h"

#include "../../../device/iccard/pboc/v2_0/PBOC_v2_0_AppAdapter.h"
using zhou_yb::device::iccard::pboc::v2_0::PBOC_v2_0_AppAdapter;
//--------------------------------------------------------- 
namespace zhou_yb {
namespace application {
namespace driver {
//--------------------------------------------------------- 
/// IC卡命令驱动
class ICCardCmdDriver : public CommonCmdDriver, public InterruptBehavior
{
protected:
    //----------------------------------------------------- 
    Ref<ITransceiveTrans> _pBaseIC;
    Ref<IICCardDevice> _pDev;
    list_t<Ref<IICCardDevice> > _icList;
    list_t<string> _argList;
    //----------------------------------------------------- 
public:
    //----------------------------------------------------- 
    ICCardCmdDriver() : CommonCmdDriver()
    {
        _RegisteCMD(ICCardCmdDriver, IsCardPresent);
        _RegisteCMD(ICCardCmdDriver, SelectSLOT);
        _RegisteCMD(ICCardCmdDriver, WaitForCard);

        _RegisteInterfaceCMD(ICCardCmdDriver, IICCardDevice);
        _RegisteInterfaceCMD(ICCardCmdDriver, ITransceiveTrans);
        
        _RegisteExceptCMD(ICCardCmdDriver);
        _RegisteIICCardCMD(ICCardCmdDriver);
        _RegisteAdapterCMD(ICCardCmdDriver);
        _RegisteCancelCMD(ICCardCmdDriver);
    }
    //----------------------------------------------------- 
    /// 选择设备,返回当前已经选择的设备
    size_t SelectDevice(const Ref<IICCardDevice>& ic, const char* powerOnArg = NULL)
    {
        size_t count = _icList.size();
        if(ic.IsNull())
            return count;
        list_t<Ref<IICCardDevice> >::iterator itr;
        for(itr = _icList.begin();itr != _icList.end(); ++itr)
        {
            if((*itr) == ic)
                return count;
        }
        _icList.push_back(ic);
        _argList.push_back(_strput(powerOnArg));

        return (count + 1);
    }
    /// 释放设备,返回当前剩余的设备
    size_t ReleaseDevice(const Ref<IICCardDevice>& ic)
    {
        size_t count = _icList.size();
        size_t index = list_helper<Ref<IICCardDevice> >::position(_icList, ic);
        if(index == SIZE_EOF)
            return count;
        list_helper<Ref<IICCardDevice> >::erase_at(_icList, index);
        list_helper<string>::erase_at(_argList, index);

        return (count - 1);
    }
    /// 释放所有设备
    void ReleaseDevice()
    {
        _icList.clear();
        _argList.clear();
        _pDev.Free();
    }
    /// 选择当前激活的卡槽
    bool SelectSLOT(size_t index)
    {
        size_t slot = index - 1;
        list_t<Ref<IICCardDevice> >::iterator itr = list_helper<Ref<IICCardDevice> >::index_of(_icList, slot);
        if(itr == _icList.end())
        {
            _logErr(DeviceError::ArgRangeErr);
            return false;
        }

        _pDev = (*itr);
        _pBaseIC = (*itr);
        return true;
    }
    //----------------------------------------------------- 
    /**
     * @brief 等待放入IC卡
     * @date 2016-05-16 21:52
     * 
     * @param [in] slot 等待放卡的卡槽,0表示自动寻卡
     * @param [in] timeoutMs 等待的超时时间
     * @param [out] pAtr [default:NULL] 获取到的ATR
     * @param [out] pIndex [default:NULL] 实际连接到的卡槽[1-N]
     */
    bool WaitForCard(size_t slot, uint timeoutMs, ByteBuilder* pAtr = NULL, size_t* pIndex = NULL)
    {
        list_t<Ref<IICCardDevice> >::iterator itr;
        list_t<string>::iterator argItr;
        if(slot > 0)
        {
            itr = list_helper<Ref<IICCardDevice> >::index_of(_icList, slot - 1);
            argItr = list_helper<string>::index_of(_argList, slot - 1);

            if(itr == _icList.end() || argItr == _argList.end())
            {
                slot = 0;
            }
        }

        size_t index = slot;
        Timer timer;
        bool bPowerOn = false;
        while(timer.Elapsed() < timeoutMs && !bPowerOn)
        {
            if(InterruptBehavior::Implement(*this))
            {
                ResetErr();
                _logErr(DeviceError::OperatorInterruptErr);
                return false;
            }
            // 自动寻卡
            if(slot == 0)
            {
                argItr = _argList.begin();
                index = 0;
                for(itr = _icList.begin();itr != _icList.end(); ++itr)
                {
                    ++index;
                    if((*itr)->PowerOn(argItr->c_str(), pAtr))
                    {
                        bPowerOn = true;
                        break;
                    }
                    ++argItr;
                }
            }
            else
            {
                if((*itr)->PowerOn(argItr->c_str(), pAtr))
                {
                    bPowerOn = true;
                }
            }
            Timer::Wait(DEV_OPERATOR_INTERVAL);
        }
        // 上电成功
        if(bPowerOn)
        {
            _pDev = (*itr);
            _pBaseIC = (*itr);
            if(pIndex != NULL)
            {
                (*pIndex) = index;
            }
            return true;
        }
        _logErr(DeviceError::DevConnectErr, "等待放卡超时");
        return false;
    }
    //----------------------------------------------------- 
    /* Interface */
    LC_CMD_INTERFACE_GETTER(IICCardDevice, _pDev);
    LC_CMD_INTERFACE_GETTER(ITransceiveTrans, _pBaseIC);
    LC_CMD_CANCEL(*this);
    LC_CMD_EXCEPT()
    {
        EXCEPT_CMD(SelectSLOT);
        EXCEPT_CMD(IsActive);
        return true;
    }
    /**
     * @brief 选择设备
     * @date 2016-08-27 14:53
     * 
     * @param [in] IICCardDevice : Ref<IICCardDevice>* 需要选择的设备
     * @param [in] Arg : string [default:""] 上电时的参数
     * 
     * @retval SLOT : size_t 当前选择的设备卡槽号
     */
    LC_CMD_METHOD(SelectDevice)
    {
        Ref<IICCardDevice> refIC = CommandReflectArg(IICCardDevice, arg);
        if(refIC.IsNull())
        {
            rlt.Put("Adapter", "IICCardDevice");
            _logErr(DeviceError::OperatorErr, "获取IICCardDevice引用失败");
            return false;
        }

        string sArg = arg["Arg"].To<string>();
        size_t count = SelectDevice(refIC, sArg.c_str());
        rlt.Put("SLOT", ArgConvert::ToString(count));
        return true;
    }
    /**
     * @brief 释放当前选择的设备
     * @date 2016-08-27 14:55
     * 
     * @param [in] IICCardDevice : Ref<IICCardDevice>* 需要释放的设备
     */
    LC_CMD_METHOD(ReleaseDevice)
    {
        Ref<IICCardDevice> refIC = CommandReflectArg(IICCardDevice, arg);
        if(!refIC.IsNull())
        { 
            ReleaseDevice(refIC);
            return true;
        }
        ReleaseDevice();
        return true;
    }
    /**
     * @brief 当前上电激活的设备
     * @date 2016-08-27 14:57
     * 
     * @retval IICCardDevice : Ref<IICCardDevice>* 当前激活的设备
     * @retval SLOT : size_t 当前激活的卡槽号
     */
    LC_CMD_METHOD(ActiveDevice)
    {
        pointer p = reinterpret_cast<pointer>(&_pDev);
        rlt.Put("IICCardDevice", ArgConvert::ToString(p));
        list_t<Ref<IICCardDevice> >::iterator itr;
        size_t index = 0;
        for(itr = _icList.begin();itr != _icList.end(); ++itr)
        {
            ++index;
            if((*itr) == _pDev)
            {
                rlt.Put("SLOT", ArgConvert::ToString(index));
                break;
            }
        }
        return true;
    }
    /**
     * @brief 判断读卡器上是否有卡
     * @date 2016-05-04 21:18
     * 
     * @param [in] SLOT : size_t 需要判断的卡片类型[1,N]
     * @return bool 有无卡
     */
    LC_CMD_METHOD(IsCardPresent)
    {
        size_t index = arg["SLOT"].To<size_t>(0);
        size_t slot = index - 1;
        list_t<Ref<IICCardDevice> >::iterator itr = list_helper<Ref<IICCardDevice> >::index_of(_icList, slot);
        if(itr == _icList.end())
        {
            _logErr(DeviceError::ArgRangeErr);
            return false;
        }
        list_t<string>::iterator argItr = list_helper<string>::index_of(_argList, slot);
        return (*itr)->PowerOn(argItr->c_str(), NULL);
    }
    /**
     * @brief 选择卡槽号
     * @date 2016-05-04 21:21
     * 
     * @param [in] SLOT : size_t 卡槽号[1,N]
     * @param [in] IsExport : bool [default:false] 是否需要导出IC卡接口
     * 
     * @return IICCardDevice : Ref<IICCardDevice>* 选择的IC卡接口
     * @return ITransceiveTrans : Ref<ITransceiveTrans>* 选择的IC卡通讯接口 
     */
    LC_CMD_METHOD(SelectSLOT)
    {
        size_t index = arg["SLOT"].To<size_t>(0);
        if(!SelectSLOT(index))
            return false;
        bool isExport = arg["IsExport"].To<bool>(false);
        if(!isExport)
            return true;

        pointer p = reinterpret_cast<pointer>(&_pDev);
        rlt.Put("IICCardDevice", ArgConvert::ToString(p));

        p = reinterpret_cast<pointer>(&_pBaseIC);
        rlt.Put("ITransceiveTrans", ArgConvert::ToString(p));
        return true;
    }
    /// 是否有卡片已经激活
    LC_CMD_METHOD(IsActive)
    {
        return !(_pDev.IsNull());
    }
    /**
     * @brief 等待放卡
     * @date 2016-05-11 21:16
     * 
     * @param [in] Timeout : uint [default:DEV_WAIT_TIMEOUT] 等待放卡的超时时间
     * @param [in] SLOT : size_t [default:0] 需要等待的卡槽[0,N]
     * 
     * @retval SLOT : size_t 实际放入的IC卡索引[1,N]
     * @retval ATR : hex 卡片的ATR信息
     */
    LC_CMD_METHOD(WaitForCard)
    {
        uint timeoutMs = arg["Timeout"].To<uint>(DEV_WAIT_TIMEOUT);
        ByteBuilder atr(8);
        size_t slot = arg["SLOT"].To<size_t>(0);
        size_t powerOnIndex = 0;

        if(WaitForCard(slot, timeoutMs, &atr, &powerOnIndex))
        {
            rlt.Put("SLOT", ArgConvert::ToString<size_t>(powerOnIndex));
            rlt.Put("ATR", ArgConvert::ToString<ByteBuilder>(atr));
            return true;
        }
        return false;
    }
    /**
     * @brief 给卡片上电
     * 
     * @param [in] Timeout : uint [default:DEV_WAIT_TIMEOUT] 等待上电的超时时间(ms)
     * @param [in] Interval : uint [default:DEV_OPERATOR_INTERVAL] 轮询时的间隔时间(ms)
     *
     * @retval ATR : hex 获取到的ATR信息
     */
    LC_CMD_METHOD(PowerOn)
    {
        // 查找对应卡槽上电时设置的参数
        size_t index = list_helper<Ref<IICCardDevice> >::position(_icList, _pDev);
        list_t<string>::iterator argItr = list_helper<string>::index_of(_argList, index);
        if(argItr == _argList.end())
        {
            _logErr(DeviceError::ArgRangeErr);
            return false;
        }

        ByteBuilder atr(16);
        Timer timer;
        uint timeoutMs = arg["Timeout"].To<uint>(DEV_WAIT_TIMEOUT);
        uint intervalMs = arg["Interval"].To<uint>(DEV_OPERATOR_INTERVAL);
        while(timer.Elapsed() < timeoutMs)
        {
            if(InterruptBehavior::Implement(*this))
            {
                ResetErr();
                _logErr(DeviceError::OperatorInterruptErr);
                return false;
            }

            if(_pDev->PowerOn(argItr->c_str(), &atr))
            {
                ByteBuilder tmp(8);
                ByteConvert::ToAscii(atr, tmp);
                rlt.Put("ATR", tmp.GetString());
                return true;
            }

            Timer::Wait(intervalMs);
        }
        ResetErr();
        _logErr(DeviceError::WaitTimeOutErr, "等待放卡超时");
        return false;
    }
    /// IC卡命令交互接口
    LC_CMD_ICCARDTRANSMIT(_pDev);
    /// 卡片下电
    LC_CMD_METHOD(PowerOff)
    {
        if(_pDev.IsNull())
            return false;

        _pDev->PowerOff();
        _pDev.Free();
        return true;
    }
    //----------------------------------------------------- 
};
//--------------------------------------------------------- 
} // nemespace driver
} // namespace application
} // namespace zhou_yb
//--------------------------------------------------------- 
#endif // _LIBZHOUYB_ICCARDCMDDRIVER_H_
//========================================================= 